<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Libs\Plugins\JPush;

use Srv\Conf\ConfModel\JVerifyConf;
use Srv\Libs\Common\CommJson;
use Srv\Libs\Common\CommNet;

class JPushVerify
{
    private int $timeOut                        = 15;       // 请求超时时长[秒]
    private string $publicPemFile               = '';       // 公钥文件路径
    private string $privatePemFile              = '';       // 私钥文件路径
    private string $appKey                      = '';       // appKey
    private string $secret                      = '';       // secret
    private string $loginTokenVerifyUrl         = 'https://api.verification.jpush.cn/v1/web/loginTokenVerify';  // loginTokenVerify API
    private string $webTokenVerifyUrl           = 'https://api.verification.jpush.cn/v1/web/verify';            // Android、iOS SDK 获取到的 token
    private string $webH5TokenVerifyUrl         = 'https://api.verification.jpush.cn/v1/web/h5/verify';         // Web SDK 获取到的 token

    /**
     * @param JVerifyConf $JVerifyConf
     * __construct
     */
    public function __construct(JVerifyConf $JVerifyConf)
    {
        $this->publicPemFile    = $JVerifyConf->getPublicPemFile();
        $this->privatePemFile   = $JVerifyConf->getPrivatePemFile();
        $this->appKey           = $JVerifyConf->getAppKey();
        $this->secret           = $JVerifyConf->getSecret();
    }

    /**
     * @param string $loginToken
     * @param string $exId
     * @param string $phoneStr
     * @return array
     * 快捷登录验证并获取手机号
     */
    public function loginTokenVerify(string $loginToken, string $exId, string &$phoneStr):array
    {
        $phoneStr       = '';
        $resData        = ['errcode' => 0, 'errmsg' => '', 'id' => '', 'extId' => '', 'phone' => ''];
        if(strlen($loginToken) < 6) return $resData;
        $postData       = [
            'loginToken'    => $loginToken,
            'exID'          => $exId,
        ];
        $postString     = json_encode($postData, JSON_UNESCAPED_UNICODE);
        $param          = [
            'TIMEOUT'   => $this->timeOut,
            'METHOD'    => 'POST',
            'USER'      => $this->appKey,
            'PASS'      => $this->secret,
            'POST_DATA' => $postString,
            'HEADER'    => ['Content-Type' => 'application/json'],
        ];
        $urlInfo        = CommNet::getUrlInfo($this->loginTokenVerifyUrl, $param);
        $bodyData       = CommJson::decodeArray($urlInfo['body']??'');
        if(isset($bodyData['code'])){
            $resData['errcode']         = intval($bodyData['code']??0);
            $resData['errmsg']          = strval($bodyData['content']??'');
            $resData['id']              = strval($bodyData['id']??'');
            $resData['extId']           = strval($bodyData['exID']??'');
            $resData['phone']           = strval($bodyData['phone']??'');
            if($resData['errcode'] === 8000 && strlen($resData['phone']) > 16) $phoneStr = $this->decrypt($resData['phone']);
        }
        return $resData;
    }

    /**
     * @param string $loginToken
     * @param string $phoneNum
     * @param string $exId
     * @param bool $verifyResult
     * @return array
     * 验证手机号
     */
    public function webTokenVerifyPhone(string $loginToken, string $phoneNum, string $exId, bool &$verifyResult):array
    {
        return $this->tokenVerifyPhone($this->webTokenVerifyUrl, $loginToken, $phoneNum, $exId, $verifyResult);
    }

    /**
     * @param string $loginToken
     * @param string $phoneStr
     * @param string $exId
     * @param bool $verifyResult
     * @return array
     * 验证手机号(webH5)
     */
    public function webH5TokenVerifyPhone(string $loginToken, string $phoneStr, string $exId, bool &$verifyResult):array
    {
        return $this->tokenVerifyPhone($this->webH5TokenVerifyUrl, $loginToken, $phoneStr, $exId, $verifyResult);
    }

    /**
     * @param string $verifyUrl
     * @param string $loginToken
     * @param string $phoneStr
     * @param string $exId
     * @param bool $verifyResult
     * @return array
     * 验证手机号
     */
    private function tokenVerifyPhone(string $verifyUrl, string $loginToken, string $phoneStr, string $exId, bool &$verifyResult):array
    {
        $verifyResult   = false;
        $resData        = ['errcode' => 0, 'errmsg' => '', 'id' => '', 'extId' => ''];
        if(strlen($verifyUrl) < 6 || strlen($loginToken) < 6 || strlen($phoneStr) !== 11) return $resData;
        $postData       = [
            'token'     => $loginToken,
            'phone'     => $phoneStr,
            'exID'      => $exId,
        ];
        $postString     = json_encode($postData, JSON_UNESCAPED_UNICODE);
        $param          = [
            'TIMEOUT'   => $this->timeOut,
            'METHOD'    => 'POST',
            'USER'      => $this->appKey,
            'PASS'      => $this->secret,
            'POST_DATA' => $postString,
            'HEADER'    => ['Content-Type' => 'application/json'],
        ];
        $urlInfo        = CommNet::getUrlInfo($verifyUrl, $param);
        $bodyData       = CommJson::decodeArray($urlInfo['body']??'');
        if(isset($bodyData['code'])){
            $resData['errcode']         = intval($bodyData['code']??0);
            $resData['errmsg']          = strval($bodyData['content']??'');
            $resData['id']              = strval($bodyData['id']??'');
            $resData['extId']           = strval($bodyData['exID']??'');
            $verifyResult               = $resData['errcode'] === 8000;     // 8000-验证成功 https://docs.jiguang.cn/jverification/server/rest_api/loginTokenVerify_api
        }
        return $resData;
    }

    /**
     * @param string $phoneDecrypt
     * @return string
     * 解密手机号数据
     */
    private function decrypt(string $phoneDecrypt):string
    {
        $phoneStr           = '';
        if(strlen($phoneDecrypt) < 1) return $phoneStr;
        $phoneDecryptSrc    = base64_decode($phoneDecrypt);
        if($phoneDecryptSrc === false || strlen($phoneDecryptSrc) < 1) return $phoneStr;
        $privatePemStr      = @file_get_contents($this->privatePemFile);
        if(!is_string($privatePemStr)) return $phoneStr;
        $privatePemStr   = trim($privatePemStr);
        if(strlen($privatePemStr) < 1) return $phoneStr;
        $pkeyId             = openssl_pkey_get_private($privatePemStr);
        if($pkeyId === false) return $phoneStr;
        $result             = '';
        if(openssl_private_decrypt($phoneDecryptSrc, $result, $pkeyId) === false) return $phoneStr;
        if(is_string($result)) $phoneStr = $result;
        return $phoneStr;
    }
}